﻿using System.Windows.Forms;
using Inovout.Gis;
using Inovout.ArcGis;
using ESRI.ArcGIS.Geodatabase;
using ESRI.ArcGIS.esriSystem;
using ESRI.ArcGIS.DataSourcesGDB;
using System.Diagnostics;
using System.Threading;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.IO;
using System;

namespace ArgGisUI
{
    public partial class MessageForm : Form
    {
        public MessageForm()
        {
            InitializeComponent();

            IFeatureWorkspace ws = CreateSdeWorkspace() as IFeatureWorkspace;
            ITable table = ws.OpenTable("XZQ");
            ICursor cursor = table.Search(null, true);
            IRow row;
            ((IWorkspaceEdit)ws).StartEditing(false);
            ((IWorkspaceEdit)ws).StartEditOperation();
            int index = table.FindField("AreaField");
            while ((row = cursor.NextRow()) != null)
            {
                row.set_Value(index, 1);
                row.Store();
            }
            ((IWorkspaceEdit)ws).StopEditOperation();
            ((IWorkspaceEdit)ws).StopEditing(true);

            // CreateCalFLMJMainThread();
            // return;

            OpenFileDialog openFileDialog = new OpenFileDialog();
            openFileDialog.CheckFileExists = true;
            openFileDialog.Multiselect = false;
            openFileDialog.RestoreDirectory = true;
            openFileDialog.Filter = "Access 文件 (*.mdb)|*.mdb";
            if (openFileDialog.ShowDialog() == DialogResult.OK)
            {
                Configuration config = new ArcGisConfiguration();
                config.Properties.Add(GisEnvironment.DatabaseTypeName, "Access");
                config.Properties.Add(GisEnvironment.AccessFileName, openFileDialog.FileName);
                SessionFactoryHolder.Instance.RegisterConfiguration(config);

                Stopwatch stopwatch = Stopwatch.StartNew();
                string[] layerNames = new string[] { "G31_H_PY" };
                //string[] layerNames = File.ReadAllLines("1.txt");
                // ImportLayer(openFileDialog.FileName, layerNames);

                LayerImporterContainer container = new LayerImporterContainer(openFileDialog.FileName, layerNames);
                container.Import();
                //  Action action = new Action(container.Import);
                // IAsyncResult result = action.BeginInvoke(null, null);
                //    result.AsyncWaitHandle.WaitOne();
                stopwatch.Stop();
                MessageBox.Show((stopwatch.ElapsedMilliseconds / 1000).ToString());
                // ImportLayerByThread(openFileDialog.FileName, layerNames);

                //  XZQMap xzqMap = MapObject.GetMap<XZQMap>();
                //   int count = xzqMap.TopXZQLayer.Geometries.Length;
            }
        }

        private void CreateCalFLMJMainThread()
        {
            Stopwatch stopwatch = Stopwatch.StartNew();

            AutoResetEvent doneEvent = new AutoResetEvent(false);
            Thread importThread = new Thread(new ParameterizedThreadStart(CreateCalFLMJThread));
            importThread.Start(doneEvent);
            doneEvent.WaitOne();
            stopwatch.Stop();

        }
        private void CreateCalFLMJThread(object state)
        {
            IFeatureWorkspace workspace = CreateSdeWorkspace() as IFeatureWorkspace;
            ITable polygonTable = workspace.OpenTable("G32_H_PL");
            int calSize = 20;
            int rowCount = polygonTable.RowCount(null);
            int calThreadCount = (rowCount % calSize == 0) ? rowCount / calSize : (rowCount / calSize + 1);
            ICursor cursor = polygonTable.Search(null, true);
            IRow row;
            int postion = 1;
            List<int> oids = new List<int>();
            List<ManualResetEvent> doneEvents = new List<ManualResetEvent>();
            int oidFieldIndex = polygonTable.FindField(polygonTable.OIDFieldName);
            while ((row = cursor.NextRow()) != null)
            {
                oids.Add(int.Parse(row.get_Value(oidFieldIndex).ToString()));
                if (postion % calThreadCount == 0)
                {
                    doneEvents.Add(new ManualResetEvent(false));
                    CalTask taskInfo = new CalTask
                    {
                        DoneEvent = doneEvents[doneEvents.Count - 1],
                        OIDS = oids.ToArray()
                    };

                    Thread thread = new Thread(new ParameterizedThreadStart(CalFLMJByThread));
                    thread.SetApartmentState(ApartmentState.STA);
                    thread.Start(taskInfo);
                    oids.Clear();
                    break;
                }
                postion++;
            }
            if (oids.Count > 0)
            {
                doneEvents.Add(new ManualResetEvent(false));
                CalTask taskInfo = new CalTask
                {
                    DoneEvent = doneEvents[doneEvents.Count - 1],
                    OIDS = oids.ToArray()
                };

                Thread thread = new Thread(new ParameterizedThreadStart(CalFLMJByThread));
                thread.SetApartmentState(ApartmentState.STA);
                thread.Start(taskInfo);

            }

            Marshal.ReleaseComObject(cursor);
            autoEvent.Set();
            WaitHandle.WaitAll(doneEvents.ToArray());


            ((AutoResetEvent)state).Set();
        }
        private class CalTask
        {
            public ManualResetEvent DoneEvent { get; set; }
            public int[] OIDS { get; set; }
        }
        private void CalFLMJByThread(object state)
        {
            CalTask task = (CalTask)state;

            IFeatureWorkspace workspace = CreateSdeWorkspace() as IFeatureWorkspace;

            IFeatureClass polygonFeatureClass = workspace.OpenFeatureClass("G32_H_PL");

            IFeatureClass lineFeatureClass = workspace.OpenFeatureClass("G32_H_PL");
            IFeatureClass pointFeatureClass = workspace.OpenFeatureClass("G33_H_PT");
            //   IFeatureCursor polygonCursor = polygonFeatureClass.Search(null, true);

            List<IFeature> fs = new List<IFeature>();
            foreach (int oid in task.OIDS)
            {
                IFeature polygonFeature = polygonFeatureClass.GetFeature(oid);
                ISpatialFilter lineSpatialFilter = new SpatialFilterClass();
                lineSpatialFilter.Geometry = polygonFeature.Shape;
                lineSpatialFilter.SpatialRel = esriSpatialRelEnum.esriSpatialRelIntersects;
                IFeature lineFeature;
                IFeatureCursor lineCursor = lineFeatureClass.Search(lineSpatialFilter, true);
                while ((lineFeature = lineCursor.NextFeature()) != null)
                {
                    object lineWidth = lineFeature.get_Value(1);
                }
                Marshal.ReleaseComObject(lineCursor);

                ISpatialFilter pointSpatialFilter = new SpatialFilterClass();
                pointSpatialFilter.Geometry = polygonFeature.Shape;
                pointSpatialFilter.SpatialRel = esriSpatialRelEnum.esriSpatialRelIntersects;
                IFeatureCursor pointCursor = pointFeatureClass.Search(pointSpatialFilter, true);
                IFeature pointFeature;
                while ((pointFeature = pointCursor.NextFeature()) != null)
                {
                    object pointAear = pointFeature.get_Value(1);
                }
                Marshal.ReleaseComObject(pointCursor);


                fs.Add(polygonFeature);
                System.Diagnostics.Trace.WriteLine(oid.ToString());
            }
            ((IMultiuserWorkspaceEdit)workspace).StartMultiuserEditing(esriMultiuserEditSessionMode.esriMESMVersioned);
            ((IWorkspaceEdit)workspace).StartEditOperation();

            foreach (var f in fs)
            {
                f.Store();
            }
            ((IWorkspaceEdit)workspace).StopEditOperation();
            try
            {
                ((IWorkspaceEdit)workspace).StopEditing(true);
            }
            catch (COMException comExc)
            {
                if (comExc.ErrorCode == (int)fdoError.FDO_E_VERSION_REDEFINED)
                {
                    IVersion version = (IVersion)workspace;
                    string versionName = version.VersionName;
                    IVersionEdit4 versionEdit4 = (IVersionEdit4)workspace;
                    lock (lockObject)
                    {
                        versionEdit4.Reconcile4(versionName, false, true, true, true);
                        ((IWorkspaceEdit)workspace).StopEditing(true);
                    }
                }
                else
                {
                    ((IWorkspaceEdit)workspace).StopEditing(false);
                }

            }
            //  Marshal.ReleaseComObject(polygonCursor);
            task.DoneEvent.Set();
        }
        private volatile object lockObject = new object();
        private void CalFLMJ()
        {
            Stopwatch stopwatch = Stopwatch.StartNew();


            IFeatureWorkspace workspace = CreateSdeWorkspace() as IFeatureWorkspace;


            IFeatureClass polygonFeatureClass = workspace.OpenFeatureClass("G31_H_PY");
            IFeatureClass lineFeatureClass = workspace.OpenFeatureClass("G32_H_PL");
            IFeatureClass pointFeatureClass = workspace.OpenFeatureClass("G33_H_PT");
            IFeatureCursor polygonCursor = polygonFeatureClass.Search(null, true);
            IFeature polygonFeature;

            ((IWorkspaceEdit)workspace).StartEditing(false);
            ((IWorkspaceEdit)workspace).StartEditOperation();
            while ((polygonFeature = polygonCursor.NextFeature()) != null)
            {
                double area = 100;
                ISpatialFilter lineSpatialFilter = new SpatialFilterClass();
                lineSpatialFilter.Geometry = polygonFeature.Shape;
                lineSpatialFilter.SpatialRel = esriSpatialRelEnum.esriSpatialRelIntersects;
                IFeature lineFeature;
                IFeatureCursor lineCursor = lineFeatureClass.Search(lineSpatialFilter, true);
                while ((lineFeature = lineCursor.NextFeature()) != null)
                {
                    object lineWidth = lineFeature.get_Value(1);
                }
                Marshal.ReleaseComObject(lineCursor);

                ISpatialFilter pointSpatialFilter = new SpatialFilterClass();
                pointSpatialFilter.Geometry = polygonFeature.Shape;
                pointSpatialFilter.SpatialRel = esriSpatialRelEnum.esriSpatialRelIntersects;
                IFeatureCursor pointCursor = pointFeatureClass.Search(pointSpatialFilter, true);
                IFeature pointFeature;
                while ((pointFeature = pointCursor.NextFeature()) != null)
                {
                    object pointAear = pointFeature.get_Value(1);
                }
                Marshal.ReleaseComObject(pointCursor);
                polygonFeature.Store();
            }

            ((IWorkspaceEdit)workspace).StopEditOperation();
            ((IWorkspaceEdit)workspace).StopEditing(true);
            Marshal.ReleaseComObject(polygonCursor);
            stopwatch.Stop();
        }

        //        static AutoResetEvent autoEvent = new AutoResetEvent(false);
        private void ImportLayer(string accessFileName, params string[] layerNames)
        {
            Stopwatch stopwatch = Stopwatch.StartNew();
            IFeatureWorkspace sourceWorkspace = CreateAccessWorkspace(accessFileName) as IFeatureWorkspace;

            IFeatureWorkspace targetWorkspace = CreateSdeWorkspace() as IFeatureWorkspace;

            ((IWorkspaceEdit)targetWorkspace).StartEditing(false);
            foreach (string layerName in layerNames)
            {
                ITable sourceTable = sourceWorkspace.OpenTable(layerName);
                ICursor sourceCursor = sourceTable.Search(null, true);
                IRow sourceRow;

                ITable targetTable = targetWorkspace.OpenTable(layerName);
                ((IWorkspaceEdit)targetWorkspace).StartEditOperation();
                while ((sourceRow = sourceCursor.NextRow()) != null)
                {
                    object shape = sourceRow.get_Value(sourceTable.Fields.FindField("Shape"));

                    IRow targetRow = targetTable.CreateRow();
                    targetRow.set_Value(targetTable.Fields.FindField("Shape"), shape);
                    targetRow.Store();
                }
                ((IWorkspaceEdit)targetWorkspace).StopEditOperation();
            }

            ((IWorkspaceEdit)targetWorkspace).StopEditing(true);

            stopwatch.Stop();
        }

        private void ImportLayerByThread(string accessFileName, params string[] layerNames)
        {
            Stopwatch stopwatch = Stopwatch.StartNew();

            AutoResetEvent doneEvent = new AutoResetEvent(false);
            ImportTaskInfo taskInfo = new ImportTaskInfo { AccessFileName = accessFileName, LayerNames = layerNames, DoneEvent = doneEvent };
            Thread importThread = new Thread(new ParameterizedThreadStart(CreateImportThread));
            importThread.Start(taskInfo);
            doneEvent.WaitOne();
            stopwatch.Stop();
        }
        private class ImportTaskInfo
        {
            public string AccessFileName { get; set; }
            public string[] LayerNames { get; set; }
            public AutoResetEvent DoneEvent { get; set; }
        }
        private void CreateImportThread(object state)
        {
            ImportTaskInfo importTaskInfo = state as ImportTaskInfo;
            List<ManualResetEvent> doneEvents = new List<ManualResetEvent>();
            string[] layerNames = importTaskInfo.LayerNames;
            string accessFileName = importTaskInfo.AccessFileName;
            IFeatureWorkspace workspace = CreateAccessWorkspace(accessFileName) as IFeatureWorkspace;
            int count = 0;
            List<string> insertLayerNames = new List<string>();
            int groupSize = 6000;

            for (int i = 0; i < layerNames.Length; i++)
            {
                string layerName = layerNames[i];
                ITable table = workspace.OpenTable(layerName);
                int rowCount = table.RowCount(null);
                if (rowCount > 0)
                {
                    //List<object> shapes = new List<object>();
                    //int shapeFieldIndex = table.FindField("Shape");
                    //ICursor sourceCursor = table.Search(null, true);
                    //IRow sourceRow;
                    //while ((sourceRow = sourceCursor.NextRow()) != null)
                    //{
                    //    shapes.Add(sourceRow.get_Value(shapeFieldIndex));
                    //}
                    insertLayerNames.Add(layerName);
                    count += rowCount;
                    if (i == layerNames.Length - 1 || count >= groupSize)
                    {
                        //#region 拆表
                        //int groupCount = rowCount / groupSize;
                        //if (rowCount > groupSize)
                        //{
                        //    for (int j = 0; j < groupCount; j++)
                        //    {
                        //        ManualResetEvent resetEvent = new ManualResetEvent(false);
                        //        doneEvents.Add(resetEvent);
                        //        TaskInfo taskInfo = new TaskInfo
                        //        {
                        //            LayerNames = new List<string>() { layerName },
                        //            DoneEvent = resetEvent,
                        //            AccessFileName = accessFileName,
                        //            MinObjectId = j * groupSize + 1,
                        //            MaxObjectId = (j + 1) * groupSize,
                        //            Shapes = null//shapes.ToArray()
                        //        };
                        //        Thread thread = new Thread(new ParameterizedThreadStart(ImportLayerTask));
                        //        thread.SetApartmentState(ApartmentState.STA);
                        //        thread.Start(taskInfo);
                        //    }
                        //}
                        //ManualResetEvent resetEvent2 = new ManualResetEvent(false);
                        //doneEvents.Add(resetEvent2);
                        //TaskInfo taskInfo2 = new TaskInfo
                        //{
                        //    LayerNames = new List<string>(insertLayerNames),
                        //    DoneEvent = resetEvent2,
                        //    AccessFileName = accessFileName,
                        //    MinObjectId = groupCount == 0 ? 0 : groupCount * groupSize + 1,
                        //    MaxObjectId = (groupCount + 1) * groupSize,
                        //    Shapes = null//shapes.ToArray()
                        //};
                        //Thread thread2 = new Thread(new ParameterizedThreadStart(ImportLayerTask));
                        //thread2.SetApartmentState(ApartmentState.STA);
                        //thread2.Start(taskInfo2);
                        //#endregion


                        #region 不拆表
                        int insertCount = (int)rowCount / 2;

                        doneEvents.Add(new ManualResetEvent(false));
                        TaskInfo taskInfo5 = new TaskInfo
                        {
                            LayerNames = new List<string>(insertLayerNames),
                            DoneEvent = doneEvents[doneEvents.Count - 1],
                            AccessFileName = accessFileName,
                            //MinObjectId = insertCount + 1,
                            //MaxObjectId = rowCount,
                            Shapes = null//shapes.ToArray()
                        };

                        Thread thread = new Thread(new ParameterizedThreadStart(ImportLayerTask));
                        thread.SetApartmentState(ApartmentState.STA);
                        thread.Start(taskInfo5);
                        #endregion

                        count = 0;
                        insertLayerNames.Clear();
                    }

                }
            }
            autoEvent.Set();
            WaitHandle.WaitAll(doneEvents.ToArray());


            importTaskInfo.DoneEvent.Set();
        }
        private AutoResetEvent autoEvent = new AutoResetEvent(false);
        private class TaskInfo
        {
            public int MinObjectId { get; set; }
            public int MaxObjectId { get; set; }
            public ManualResetEvent DoneEvent { get; set; }
            public List<string> LayerNames { get; set; }
            public string AccessFileName { get; set; }
            public object[] Shapes { get; set; }
        }
        private void ImportLayerTask(object state)
        {
            TaskInfo taskInfo = state as TaskInfo;

            //string layerName = taskInfo.LayerName;
            IFeatureWorkspace sourceWorkspace = CreateAccessWorkspace(taskInfo.AccessFileName) as IFeatureWorkspace;
            IFeatureWorkspace targetWorkspace = CreateSdeWorkspace() as IFeatureWorkspace;

            //IFeatureDataset featureDataset = targetWorkspace.OpenFeatureDataset("TDLYGH");
            //ITopologyContainer topologyContainer = (ITopologyContainer)featureDataset;
            //ITopology topology = topologyContainer.get_Topology(0); 
            //IDataset sd = topology as IDataset;
            //((ITopologyProperties)topology).Classes.Next().CLSID.Value

            ((IMultiuserWorkspaceEdit)targetWorkspace).StartMultiuserEditing(esriMultiuserEditSessionMode.esriMESMVersioned);
            foreach (string layerName in taskInfo.LayerNames)
            {
                ITable sourceTable = sourceWorkspace.OpenTable(layerName);
                int sourceShapeFieldIndex = sourceTable.Fields.FindField("Shape");
                //autoEvent.WaitOne();
                //List<object> shapes = new List<object>();
                int shapeFieldIndex = sourceTable.FindField("Shape");
                IQueryFilter queryFilter = null;
                if (taskInfo.MinObjectId > 0)
                {
                    queryFilter = new QueryFilterClass();

                    queryFilter.WhereClause = string.Format("ObjectId >= {0} AND ObjectId <={1}", taskInfo.MinObjectId.ToString(), taskInfo.MaxObjectId.ToString());
                }
                ICursor sourceCursor = sourceTable.Search(queryFilter, true);
                IRow sourceRow;
                //while ((sourceRow = sourceCursor.NextRow()) != null)
                //{
                //    shapes.Add(sourceRow.get_Value(shapeFieldIndex));
                //}
                //autoEvent.Set();
                ITable targetTable = targetWorkspace.OpenTable(layerName);
                //IVersionedObject versionObject = targetTable as IVersionedObject;
                //if (versionObject.IsRegisteredAsVersioned)
                //{
                //    //         autoEvent.WaitOne();
                //    ((IMultiuserWorkspaceEdit)targetWorkspace).StartMultiuserEditing(esriMultiuserEditSessionMode.esriMESMVersioned);
                //    //    autoEvent.Set();

                //}
                //else
                //{
                //    ((IMultiuserWorkspaceEdit)targetWorkspace).StartMultiuserEditing(esriMultiuserEditSessionMode.esriMESMNonVersioned);
                //}
                ((IWorkspaceEdit)targetWorkspace).StartEditOperation();
                int targetShapeFieldIndex = targetTable.Fields.FindField("Shape");
                //  foreach(object shape in shapes)
                ICursor targetCursor = targetTable.Insert(true);
                while ((sourceRow = sourceCursor.NextRow()) != null)
                {
                    object shape = sourceRow.get_Value(sourceShapeFieldIndex);


                    IRowBuffer targetRowBuffer = targetTable.CreateRowBuffer();
                    targetRowBuffer.set_Value(targetTable.Fields.FindField("Shape"), shape);
                    targetCursor.InsertRow(targetRowBuffer);

                    //IRow targetRow = targetTable.CreateRow();
                    //targetRow.set_Value(targetShapeFieldIndex, shape);
                    //targetRow.Store();


                }
                ((IWorkspaceEdit)targetWorkspace).StopEditOperation();
                //    Marshal.ReleaseComObject(sourceCursor);
                //    Marshal.ReleaseComObject(targetCursor);
            }

            try
            {
                ((IWorkspaceEdit)targetWorkspace).StopEditing(true);
            }
            catch (COMException comExc)
            {
                if (comExc.ErrorCode == (int)fdoError.FDO_E_VERSION_REDEFINED)
                {
                    IVersion version = (IVersion)targetWorkspace;
                    string versionName = version.VersionName;
                    IVersionEdit4 versionEdit4 = (IVersionEdit4)targetWorkspace;
                    //      autoEvent.WaitOne();
                    lock (lockObject)
                    {
                        autoEvent.WaitOne();
                        bool suc = versionEdit4.Reconcile4(versionName, true, true, false, false);


                        //if (versionEdit4.CanPost())
                        //{
                        //    versionEdit4.Post(versionEdit4.PreReconcileVersion.VersionName);
                        //}
                        System.Diagnostics.Trace.WriteLine("协调成功！");
                        ((IWorkspaceEdit)targetWorkspace).StopEditing(true);


                        autoEvent.Set();
                    }
                }
                else
                {
                    throw comExc;
                }

            }
            //  Marshal.ReleaseComObject(sourceTable);
            //   Marshal.ReleaseComObject(sourceWorkspace);

            //   Marshal.ReleaseComObject(sourceCursor);

            //Marshal.ReleaseComObject(targetTable);
            //Marshal.ReleaseComObject(targetWorkspace);

            taskInfo.DoneEvent.Set();
        }

        private IWorkspace CreateFileGDBWorkspace(string fileName)
        {
            fileName = Path.GetDirectoryName(fileName);
            IPropertySet propertySet = new PropertySetClass();
            propertySet.SetProperty("DATABASE", fileName);


            IWorkspaceFactory2 workspaceFactory = new FileGDBWorkspaceFactoryClass();
            return workspaceFactory.Open(propertySet, 0);
        }

        private IWorkspace CreateAccessWorkspace(string accessFileName)
        {
            IPropertySet propertySet = new PropertySetClass();
            propertySet.SetProperty("DATABASE", accessFileName);

            IWorkspaceFactory2 workspaceFactory = new AccessWorkspaceFactoryClass();
            return workspaceFactory.Open(propertySet, 0);
        }

        private IWorkspace CreateSdeWorkspace()
        {
            IPropertySet propertySet = new PropertySetClass();
            propertySet.SetProperty("SERVER", "172.18.6.24");
            propertySet.SetProperty("INSTANCE", "5151");
            propertySet.SetProperty("DATABASE", "sde");
            propertySet.SetProperty("USER", "sde");
            propertySet.SetProperty("PASSWORD", "sde");
            propertySet.SetProperty("VERSION", "sde.DEFAULT");
            IWorkspaceFactory2 workspaceFactory = new SdeWorkspaceFactoryClass();
            return workspaceFactory.Open(propertySet, 0);

        }

    }
}
